﻿/**
*  @author alex
*/

Namespace("sketch.framework");
(function () {
    var fwk = sketch.framework;

    //TODO: refactor - just extend array
    fwk.OrderedCollection = function(){
        var items = [];
        this.changed = fwk.EventHelper.createEvent();
        
        this.add = function(element){
            var length = items.length;
            var order = element.zOrder();
            if(order === null){
                order = element.zOrder(length + 1);
            }

            var inserted = false;
			for (var i = length - 1; i >= 0; --i) {
                if(items[i].zOrder() <= order){
                    items.splice(i + 1, 0, element);
                    inserted = true;
                    break;
                }
            }

            if(!inserted){
                items.unshift(element);
            }            

            this.changed({
                action:"added",
                element:element
            });
        };

        this.remove = function(element){
            for (var i = items.length - 1; i >= 0; i--) {
                if(items[i] === element){
                    items.splice(i,1);
                    this.changed({
                        action:"removed",
                        element:element
                    });
                    return;
                }
            } 
        };

        this.clear = function(){
            items = [];
            this.changed({
                action:"cleared"
            });
        };

        this.each = function(callback){
            for (var i = 0, length = items.length; i < length; i++) {
                if(callback(i, items[i])===false){
                    return;
                }
            }
        };

        this.eachReverse = function(callback){
            for (var i =  items.length - 1; i >= 0; i--) {
                if(callback(i, items[i])===false){
                    return;
                }
            }
        };

        this.all = function(predicate, callback){
            this.each(function(i, item){
                if(predicate(i, item)){
                    if(callback(i, item)===false){
                        return false;
                    }
                }
            });            
        };

        this.allReverse = function(predicate, callback){
            this.eachReverse(function(i, item){
                if(predicate(i, item)){
                    if(callback(i, item)===false){
                        return false;
                    }
                }
            });            
        };

        this.where = function(predicate){
            var result = [];
            this.each(function(i, item){
                if (predicate(item) === true){
                    result.push(item);
                }
            });
            return result;
        },
        this.single = function(predicate){
            var result = this.singleOrDefault(predicate);

            if (!result){
                throw new Error("No elements match the predicate");
            }
            return result;
        };
        this.singleOrDefault = function(predicate){
            var result = this.where(predicate);

            if (result.length === 0){
                return null;
            }
            if (result.length > 1){
                throw new Error("More than one element matches the predicate");
            }
            return result[0];
        };

        this.count = function(){
            return items.length;
        };

        this.top = function(){
            if(items.length === 0){
                return null;
            }
            return items[items.length-1];
        },

        this.positionOf = function(element){
            return items.indexOf(element);
        };

        this.insert = function(element, index){
            items.splice(index, 0, element);
            for (var i = index; i < items.length; i++) {
                if(i > 0){
                    if(items[i].zOrder() <= items[i-1].zOrder()){
                        items[i].zOrder(items[i-1].zOrder() + 1);
                    }
                }
            }

            this.changed({
                action:"added",
                element:element
            });
        };

        this.changePosition = function(element, index){
            for (var i = items.length - 1; i >= 0; i--) {
                if(items[i] === element){
                    items.splice(i,1);
                    break;
                }
            }

            items.splice(index, 0, element);
            for (i = index; i < items.length; i++) {
                if(i > 0){
                    if(items[i].zOrder() <= items[i-1].zOrder()){
                        items[i].zOrder(items[i-1].zOrder() + 1);
                    }
                }
            }

            this.changed({
                action:"position",
                element:element
            });
        };

        this.toArray = function(){
            return items.slice(0);
        };
    }
})();